﻿using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading.Tasks;

namespace Order
{
    public class OrderService : DbContext
    {
        public DbSet<Order> Orders { get; init; }

        public OrderService(DbContextOptions<OrderService> options) : base(options)
        {
            Database.EnsureCreated();
        }
        public OrderService() : base()
        {
            Database.EnsureCreated();
        }
        public enum InquiryType
        {
            OrderID, CommodityName, CustomerName, Total, All
        }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            //_con = GetConnection();
            optionsBuilder.UseInMemoryDatabase("OrderDB");
        }
        //public override void Dispose()
        //{
        //    base.Dispose();
        //    //_con.Dispose();
        //    GC.SuppressFinalize(this);
        //}

        //static DbConnection GetConnection()
        //{
        //    var connection = new SqliteConnection("data source=.\\data.db");
        //    connection.Open();
        //    return connection;
        //}

        public async Task AddOrder(Order order)
        {
            Orders.Add(order);
            await SaveChangesAsync();
        }
        public async Task DeleteOrder(string orderID)
        {
            var deorder = await InquiryOrdersAsync(orderID, InquiryType.OrderID);
            deorder.ForEach(o => o.OrderDetails.Clear());
            Orders.RemoveRange(deorder);
            await SaveChangesAsync();
        }
        public async Task ModifyOrder(string orderID, Order newOrder)
        {
            var deorder = await InquiryOrdersAsync(orderID, InquiryType.OrderID);
            if (!deorder.Any())
                throw new KeyNotFoundException("The order matching the given id not found.");
            Orders.RemoveRange(deorder);
            Orders.Add(newOrder);
            await SaveChangesAsync();
        }
        public async Task<List<Order>> InquiryOrdersAsync(string info, InquiryType type)
        {
            System.Linq.Expressions.Expression<Func<Order, bool>> condition = type switch
            {
                InquiryType.OrderID => order => order.OrderID.Contains(info),
                InquiryType.CustomerName => order => order.TheCustomer.Name.Contains(info),
                InquiryType.CommodityName => order => order.OrderDetails.Exists(detail => detail.Commodity.Name.Contains(info)),
                InquiryType.Total => order => order.Total.ToString() == info,
                InquiryType.All => order => true,
                _ => throw new ArgumentException("Inquiry type invalid"),
            };
            var query = Orders.Include(o => o.OrderDetails)
                .Where(condition);
            return await query.ToListAsync();
        }
        public void Export(Stream stream)
        {
            DataContractSerializer serializer = new(typeof(DbSet<Order>));
            serializer.WriteObject(stream, Orders);
        }
        public async Task Import(Stream stream)
        {
            DataContractSerializer serializer = new(typeof(DbSet<Order>));
            var imported = serializer.ReadObject(stream) as DbSet<Order>;
            Orders.AddRange(imported);
            await SaveChangesAsync();
        }
    }
}
